/*
 *  IIS.cpp
 *  TubeTruck
 *
 *  Created by Aeturnum on 6/4/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "IIS.h"

using namespace TTP;
using namespace std;

IIS::IIS() : Packet(Packet_IIS), mGroupCount(0), mAppDataLength(0)
{}
IIS(id_hash idHash) : Packet(idHash, Packet_IIS)
IIS::IIS(id_hash idHash, vector<byte>& pubKey, vector< vector<byte> >& multicastAddrs, vector< vector<byte> >& groupKeys) :
Packet(idHash, Packet_IIS), mDestHash(0), mPubKey(pubKey), 
mGroupCount(groupKeys.size()), mMulticastAddrs(multicastAddrs), mGroupKeys(groupKeys),
mAppDataLength(0)
{
   if(mMulticastAddrs.size() != mGroupKeys.size())
      throw msg_exception("TTP::IIS - List of multicast groups and multicast keys not same size.");
}
IIS::IIS(id_hash idHash, vector<byte>& pubKey, vector< vector<byte> >& multicastAddrs, vector< vector<byte> >& groupKeys, vector<byte>& data) :
Packet(idHash, Packet_IIS), mDestHash(0), mPubKey(pubKey), 
mGroupCount(groupKeys.size()), mMulticastAddrs(multicastAddrs), mGroupKeys(groupKeys),
mAppDataLength(data.size()), mAppData(data)
{
   if(mMulticastAddrs.size() != mGroupKeys.size())
      throw msg_exception("TTP::IIS - List of multicast groups and multicast keys not same size.");
}
IIS::~IIS() {}

// accessors
vector<byte> IIS::getPubKey() const {
   return mPubKey;
}

byte IIS::getGroupcount() const {
   return mGroupCount;
}

vector<byte> IIS::getMcastAddr(byte n) const {
   return mMulticastAddrs[n];
}

vector<byte> IIS::getGroupKey(byte n) const {
   return mGroupKeys[n];
}

vector< vector<byte> > IIS::getMcastAddrs() const {
   return mMulticastAddrs;
}

vector< vector<byte> > IIS::getGroupKeys() const {
   return mGroupKeys;
}

unsigned short IIS::getAppDataLength() const {
   return mAppDataLength;
}

vector<byte> IIS::getAppData() const {
   return mAppData;
}

// modifiers
void IIS::setPubKey(vector<byte>& publicKey) {
   mPubKey = publicKey;
}
void IIS::addMulticastGroup(vector<byte>& mcastAddr, vector<byte>& groupPublicKey) {
   mMulticastAddrs.push_back(mcastAddr);
   mGroupKeys.push_back(groupPublicKey);
   ++mGroupCount;
}

void IIS::addMulticastGroup(Group& g) {
   mMulticastAddrs.push_back(g.mAddress);
   mGroupKeys.push_back(g.getGroupRSA().getPublicKey());
   ++mGroupCount;
}

void IIS::addAppData(vector<byte>& newData) {
   mAppData.insert(mAppData.end(), newData.begin(), newData.end());
   mAppDataLength += newData.size();
}

// idHash
void IIS::setSourceIdHash(id_hash idHash) {
   mIdHash = idHash;
}

id_hash IIS::getSourceIdHash() const {
   return mIdHash;
}

void IIS::setDestIdHash(id_hash idHash) {
   mDestHash = idHash;
}
id_hash IIS::getDestIdHash() const {
   return mDestHash;
}

// inherited
void IIS::fromVec(vector<byte>::const_iterator &vit, const vector<byte>::const_iterator &end){
//   cout << "\n\nFromvec:";
   Packet::fromVec(vit, end);
   unserialize(vit, end, mDestHash);
   hashFromVec(vit);
   
   mPubKey.clear();
   mPubKey.insert(mPubKey.end(), vit, vit+ Crypt::RSA::RSAKeyLength);
   vit = vit + Crypt::RSA::RSAKeyLength;
//   cout << "PubKey(" << mPubKey.size() << "):\n" << mPubKey;
   
   mGroupCount = *vit++;
   for(byte i = 0; i < mGroupCount; i++) {
      vector<byte> multicastAddr, multicastKey;
      multicastAddr.insert(multicastAddr.end(), vit, vit+IIS_mcastAddrLength);
      vit = vit + IIS_mcastAddrLength;
      
      multicastKey.insert(multicastKey.end(), vit, vit + Crypt::RSA::RSAKeyLength);
      vit = vit + Crypt::RSA::RSAKeyLength;
      
      mMulticastAddrs.insert(mMulticastAddrs.end(), multicastAddr) ;
      mGroupKeys.insert(mGroupKeys.end(), multicastKey);
//      cout << "McastAddr["<< (int)i << "](" << mMulticastAddrs[i].size() << "):\n" << mMulticastAddrs[i]; 
//      cout << "groupKey["<< (int)i << "](" << mGroupKeys[i].size() << "):\n" << mGroupKeys[i];
   }
   
   mAppDataLength = 0;
   mAppData.clear();
   unserialize<unsigned short>(vit, end, mAppDataLength);
   mAppData.insert(mAppData.end(), vit, vit + mAppDataLength);
//   cout << "AppData(" << mAppData.size() << "/" << mAppDataLength << "):\n" << mAppData;
   vit = vit + mAppDataLength;
   
   
   if(!verifyHash()) {
      throw msg_exception("IIS failed to varify hash value!!");
   }
}

void IIS::toVec(vector<byte> &vec) const {
   createHash();
//   cout << "Tovec:";
   Packet::toVec(vec);
   serialize(vec, mDestHash);
   hashToVec(vec);
   
//   cout << "PubKey(" << mPubKey.size() << "):\n" << mPubKey;
   vec.insert(vec.end(), mPubKey.begin(), mPubKey.end());
   vec.push_back(mGroupCount);
   
   for(byte i = 0; i < mGroupCount; i++ ) {
//      cout << "McastAddr["<< i << "](" << mMulticastAddrs[i].size() << "):\n" << mMulticastAddrs[i]; 
      vec.insert(vec.end(), mMulticastAddrs[i].begin(), mMulticastAddrs[i].end());
//      cout << "groupKey["<< i << "](" << mGroupKeys[i].size() << "):\n" << mGroupKeys[i];
      vec.insert(vec.end(), mGroupKeys[i].begin(), mGroupKeys[i].end());
   }
   
//   cout << "AppData(" << mAppData.size() << "/" << mAppDataLength << "):\n" << mAppData;
   serialize<unsigned short>(vec, mAppDataLength);
   vec.insert(vec.end(), mAppData.begin(), mAppData.end());
}


vector<byte> IIS::getHashablePacket() const {
   vector<byte> vec;
   vector<byte> fakeHash(getBlankHash());
   
   Packet::toVec(vec);
   serialize(vec, mDestHash);
   vec.insert(vec.end(), fakeHash.begin(), fakeHash.end());
   
   vec.insert(vec.end(), mPubKey.begin(), mPubKey.end());
   vec.push_back(mGroupCount);
   
   for(byte i = 0; i < mGroupCount; i++ ) {
      vec.insert(vec.end(), mMulticastAddrs[i].begin(), mMulticastAddrs[i].end());
      vec.insert(vec.end(), mGroupKeys[i].begin(), mGroupKeys[i].end());
   }
   
   vec.push_back(mAppDataLength);
   vec.insert(vec.end(), mAppData.begin(), mAppData.end());   
   return vec;
}
